#include "timeout.h"
#include "parafluidorientation.h"
#include "parafluidsimulation.h"

using namespace ParaFluid;

Simulation * Simulation::_instance;

Simulation::~Simulation()
{
	/* does nothing */
}

Simulation::Simulation()
	: QThread()
	, _continue(false)
	, _semaphoreStep()
	, _sph(0)
	, _mutexSPH()
	//, _mesh(":cube.obj")
	, _mesh(":motton.obj")
	, _emitter()
{
	resetSPH(defaultBuckets(), defaultAtoms(), defaultSubstance(), 1, Vector(1.0, 1.0, 1.0));
}


Simulation & Simulation::instance()
{
	if(!_instance)
	{
		_instance = new Simulation();
	}
	return *_instance;
}

const Substance & Simulation::defaultSubstance()
{
	return Substance::WATER;
}

int Simulation::defaultAtoms()
{
	return 1000;
}

int Simulation::defaultBuckets()
{
	return 2000;
}

SPH & Simulation::sph()
{
	return *_sph;
}

void Simulation::resetSPH(int buckets, int atoms, const Substance & substance, int rate, const Vector & emitterPosition)
{
	_mutexSPH.lock();
	
	delete _sph;
	_sph = new SPH(_mesh.triangles.size(), buckets, 3.0, 0.1, Vector(0.0, 0.0, 0.0));
	
	// Insert Triangles again
	for(int i = 0; i < _mesh.triangles.size(); ++i)
	{
		_sph->triangleVoxelizer.insert(_mesh.triangles.at(i));
	}
	
	_mutexSPH.unlock();
	
	_emitter.setRate(rate);
	_emitter.setRemaining(atoms);
	_emitter.substance = substance;
	_emitter.zone.position = emitterPosition;
	
	
	emit reseted();
}

void Simulation::pause()
{
	if(isRunning())
	{
		_continue = false;
	}
	else
	{
		_continue = true;
		start();
	}
}

void Simulation::nextStep()
{
	_semaphoreStep.release();
}

void Simulation::run()
{
	Timing::Timeout nextStep;
	
	while(_continue)
	{
		nextStep.timeOutIn(0.0166667);
		
		_mutexSPH.lock();
		_emitter.emitAtoms(*_sph);
		_sph->step();
		_mutexSPH.unlock();
		
		emit stepped();
		
		while(nextStep.hasNotTimedOut())
		{
			Timing::Timeout::sleep(0.005);
		}
		
		_semaphoreStep.acquire();
	}
}
